/**
 * WebSocket客户端工具类
 * 封装WebSocket连接和消息处理的通用功能
 */
class WebSocketClient {
    /**
     * 构造函数
     * @param {string} endpoint WebSocket端点URL
     * @param {string} username 用户名
     * @param {Object} callbacks 回调函数对象
     */
    constructor(endpoint, username, callbacks = {}) {
        this.endpoint = endpoint;
        this.username = username;
        this.connected = false;
        this.reconnectAttempts = 0;
        this.maxReconnectAttempts = 5;
        this.reconnectDelay = 3000;
        this.reconnecting = false;
        this.socket = null;
        this.messageQueue = [];
        
        // Constants
        this.MAX_MESSAGE_SIZE = 64 * 1024; // 64KB max message size
        this.CHUNK_SIZE = 16 * 1024;       // 16KB chunk size for splitting
        
        // 回调函数
        this.callbacks = {
            onConnect: callbacks.onConnect || function() {},
            onDisconnect: callbacks.onDisconnect || function() {},
            onMessage: callbacks.onMessage || function() {},
            onError: callbacks.onError || function() {},
            onReconnect: callbacks.onReconnect || function() {},
            onReconnectFailed: callbacks.onReconnectFailed || function() {}
        };
    }
    
    /**
     * 初始化WebSocket连接
     */
    connect() {
        if (this.socket && (this.socket.readyState === WebSocket.OPEN || this.socket.readyState === WebSocket.CONNECTING)) {
            console.log("WebSocket连接已存在");
            return;
        }
        
        try {
            // Determine protocol (ws or wss)
            const protocol = window.location.protocol === 'https:' ? 'wss://' : 'ws://';
            const host = window.location.hostname;
            const port = window.location.port;
            const baseUrl = protocol + host + (port ? ':' + port : '');
            
            // Add leading slash if needed
            let path = this.endpoint;
            if (!path.startsWith('/')) {
                path = '/' + path;
            }
            
            // Append username as query parameter
            const wsUrl = baseUrl + path + '?username=' + encodeURIComponent(this.username);
            
            // Create WebSocket connection
            this.socket = new WebSocket(wsUrl);
            
            // Set up event handlers
            this.socket.onopen = (event) => this.handleOpen(event);
            this.socket.onclose = (event) => this.handleClose(event);
            this.socket.onmessage = (event) => this.handleMessage(event);
            this.socket.onerror = (event) => this.handleError(event);
            
            console.log("正在连接WebSocket...");
        } catch (error) {
            console.error("WebSocket连接初始化失败:", error);
            this.callbacks.onError(error);
        }
    }
    
    /**
     * 处理WebSocket连接打开事件
     */
    handleOpen(event) {
        console.log("WebSocket连接已建立");
        this.connected = true;
        this.reconnectAttempts = 0;
        this.reconnecting = false;
        
        // 连接成功后，发送队列中的消息
        this.sendQueuedMessages();
        
        // 调用连接回调
        this.callbacks.onConnect(event);
    }
    
    /**
     * 处理WebSocket连接关闭事件
     */
    handleClose(event) {
        if (this.connected) {
            console.log("WebSocket连接已关闭", event);
            this.connected = false;
            
            // 调用断开连接回调
            this.callbacks.onDisconnect(event);
            
            // 尝试重连（除非是明确的关闭）
            if (!this.reconnecting && event.code !== 1000) {
                this.attemptReconnect();
            }
        }
    }
    
    /**
     * 处理WebSocket消息事件
     */
    handleMessage(event) {
                let message;
        
                try {
                    message = JSON.parse(event.data);
                } catch (e) {
            console.error('Failed to parse message:', e);
            message = { type: 'error', content: 'Invalid message format' };
        }
        
        // Call message callback if provided
        if (this.callbacks.onMessage) {
            this.callbacks.onMessage(message);
        }
    }

    /**
     * 处理WebSocket错误事件
     */
    handleError(event) {
        console.error("WebSocket错误:", event);
        this.callbacks.onError(event);
    }
    
    /**
     * 重连WebSocket
     */
    attemptReconnect() {
        if (this.reconnectAttempts >= this.maxReconnectAttempts) {
            if (this.callbacks.onReconnectFailed) {
                this.callbacks.onReconnectFailed();
            }
            return;
        }
        
        this.reconnecting = true;
        this.reconnectAttempts++;
        
        console.log(`WebSocket尝试重连 (${this.reconnectAttempts}/${this.maxReconnectAttempts})...`);
        
        // 调用重连回调
        this.callbacks.onReconnect(this.reconnectAttempts, this.maxReconnectAttempts);
        
        // 延迟重连
        setTimeout(() => {
            try {
            this.connect();
            } catch (e) {
                console.error('Reconnect attempt failed:', e);
                this.attemptReconnect();
            }
        }, this.reconnectDelay);
    }
    
    /**
     * 发送消息到服务器
     * @param {Object} message 消息对象
     */
    send(message) {
        if (!message) {
            console.error("无效的消息");
            return false;
        }
        
        // 添加消息ID和时间戳（如果没有）
        if (!message.messageId) {
            message.messageId = this.generateUUID();
        }
        if (!message.timestamp) {
            message.timestamp = Date.now();
        }
        
        // 如果WebSocket连接可用，直接发送
        if (this.connected && this.socket && this.socket.readyState === WebSocket.OPEN) {
            try {
                const messageString = JSON.stringify(message);
                
                // Check for message size limitation
                if (messageString.length > this.MAX_MESSAGE_SIZE) {
                    console.warn('Message exceeds max size and will be chunked');
                    this.sendLargeMessage(message);
                } else {
                    this.socket.send(messageString);
                }
                
                return true;
        } catch (error) {
                console.error("消息发送失败:", error);
                // 发送失败，加入队列
                this.messageQueue.push(message);
                return false;
            }
        } else {
            // WebSocket不可用，加入队列
            console.log("WebSocket不可用，消息已加入队列");
            this.messageQueue.push(message);
            
            // 如果未连接，尝试连接
            if (!this.connected) {
                this.connect();
            }
            
            return false;
        }
    }
    
    /**
     * 发送文本聊天消息
     * @param {string} toUser 接收者用户名
     * @param {string} content 消息内容
     */
    sendTextMessage(toUser, content) {
        return this.send({
            type: "chat",
            fromUser: this.username,
            toUser: toUser,
            contentType: "text",
            content: content
        });
    }
    
    /**
     * 发送媒体消息
     * @param {string} toUser 接收者用户名
     * @param {string} contentType 内容类型 (image/video/audio/file)
     * @param {string} content Base64编码的媒体内容
     * @param {string} fileName 文件名 (可选)
     * @param {string} fileExtension 文件扩展名 (可选)
     * @param {number} fileSize 文件大小 (可选)
     */
    sendMediaMessage(toUser, contentType, content, fileName, fileExtension, fileSize) {
        // For media content, always check size and use chunking if needed
        const message = {
            type: 'chat',
            contentType: contentType,
            toUser: toUser,
            fromUser: this.username,
            content: content,
            fileName: fileName,
            fileExt: fileExtension,
            fileSize: fileSize,
            timestamp: new Date().getTime()
        };
        
        // Always use chunking for media messages
        if (content && content.length > this.CHUNK_SIZE) {
            return this.sendLargeMessage(message);
        } else {
            return this.send(message);
        }
    }
    
    /**
     * 分块发送大文件
     * @param {string} toUser 接收者用户名
     * @param {string} contentType 内容类型
     * @param {Array<string>} chunks Base64编码的文件分块
     * @param {string} fileName 文件名
     * @param {string} fileExtension 文件扩展名
     * @param {number} fileSize 文件大小
     */
    sendLargeFile(toUser, contentType, chunks, fileName, fileExtension, fileSize) {
        // Initial metadata message
        const fileId = 'file_' + Date.now() + '_' + Math.random().toString(36).substring(2, 15);
        
        this.send({
            type: 'media_transfer_start',
            contentType: contentType,
            toUser: toUser,
            fromUser: this.username,
            fileName: fileName,
            fileExt: fileExtension,
            fileSize: fileSize,
            fileId: fileId,
            totalChunks: chunks.length,
            timestamp: new Date().getTime()
        });
        
        // Send each chunk with a small delay
        chunks.forEach((chunk, index) => {
            setTimeout(() => {
                this.send({
                    type: 'media_transfer',
                    contentType: contentType,
                    toUser: toUser,
                    fromUser: this.username,
                    fileId: fileId,
                    chunkIndex: index,
                    totalChunks: chunks.length,
                    chunk: chunk,
                    timestamp: new Date().getTime()
                });
                
                // If this is the last chunk, send completion message
                if (index === chunks.length - 1) {
                    setTimeout(() => {
                        this.send({
                            type: 'media_transfer_complete',
                            contentType: contentType,
                            toUser: toUser,
                            fromUser: this.username,
                            fileId: fileId,
                            fileName: fileName,
                            fileExt: fileExtension,
                            fileSize: fileSize,
                            timestamp: new Date().getTime()
                        });
                    }, 500);
                }
            }, index * 200); // Add delay between chunks to prevent overwhelming the server
        });
    }
    
    /**
     * 发送好友请求
     * @param {string} toUser 接收者用户名
     * @param {string} message 附加消息
     */
    sendFriendRequest(toUser, message = "") {
        return this.send({
            type: "friend_request",
            fromUser: this.username,
            toUser: toUser,
            contentType: "text",
            content: message
        });
    }
    
    /**
     * 发送好友请求响应
     * @param {string} toUser 接收者用户名
     * @param {boolean} accepted 是否接受
     */
    sendFriendResponse(toUser, accepted) {
        return this.send({
            type: "friend_response",
            fromUser: this.username,
            toUser: toUser,
            contentType: "text",
            content: accepted.toString()
        });
    }
    
    /**
     * 发布朋友圈内容
     * @param {string} contentType 内容类型
     * @param {string} content 内容
     */
    publishSocialPost(contentType, content) {
        return this.send({
            type: "social_post",
            fromUser: this.username,
            contentType: contentType,
            content: content
        });
    }

    /**
     * 发送社交互动（点赞、评论等）
     * @param {string} toUser 帖子所有者
     * @param {string} postId 帖子ID
     * @param {string} interactionType 互动类型 (like/comment/share)
     * @param {string} content 互动内容（评论内容等）
     */
    sendSocialInteraction(toUser, postId, interactionType, content = "") {
        return this.send({
            type: "social_interaction",
            fromUser: this.username,
            toUser: toUser,
            contentType: "text",
            content: interactionType,
            relatedMessageId: postId,
            extraContent: content
        });
    }
    
    /**
     * 发送正在输入指示器
     * @param {string} toUser 接收者用户名
     */
    sendTypingIndicator(toUser) {
        return this.send({
            type: "typing",
            fromUser: this.username,
            toUser: toUser,
            contentType: "text"
        });
    }
    
    /**
     * 发送已读回执
     * @param {string} toUser 原消息发送者
     * @param {string} messageId 消息ID
     */
    sendReadReceipt(toUser, messageId) {
        return this.send({
            type: "read_receipt",
            fromUser: this.username,
            toUser: toUser,
            contentType: "text",
            relatedMessageId: messageId
        });
    }
    
    /**
     * 主动关闭WebSocket连接
     */
    disconnect() {
        if (this.socket) {
            this.reconnecting = false; // 防止自动重连
            this.socket.close(1000, "Client disconnected");
            console.log("WebSocket连接已主动关闭");
        }
    }
    
    /**
     * 发送队列中的消息
     */
    sendQueuedMessages() {
        if (this.messageQueue.length === 0) {
            return;
        }
        
        console.log(`发送队列中的消息 (${this.messageQueue.length}条)...`);
        
        // 创建队列副本并清空原队列
        const queueCopy = [...this.messageQueue];
        this.messageQueue = [];
        
        // 发送所有队列消息
        queueCopy.forEach(message => {
            if (!this.send(message)) {
                // 如果发送失败，重新加入队列
                this.messageQueue.push(message);
            }
        });
    }
    
    /**
     * 发送大消息
     * @param {Object} message 消息对象
     */
    sendLargeMessage(message) {
        const messageString = JSON.stringify(message);
        const totalChunks = Math.ceil(messageString.length / this.CHUNK_SIZE);
        
        // Send metadata about chunked transfer
        const metadataMessage = {
            type: 'chunk_metadata',
            originalType: message.type,
            contentType: message.contentType,
            totalChunks: totalChunks,
            totalSize: messageString.length,
            messageId: 'msg_' + Date.now() + '_' + Math.random().toString(36).substring(2, 15)
        };
        
        this.socket.send(JSON.stringify(metadataMessage));
        
        // Send each chunk
        for (let i = 0; i < totalChunks; i++) {
            const start = i * this.CHUNK_SIZE;
            const end = Math.min((i + 1) * this.CHUNK_SIZE, messageString.length);
            const chunk = messageString.substring(start, end);
            
            const chunkMessage = {
                type: 'chunk',
                messageId: metadataMessage.messageId,
                chunkIndex: i,
                totalChunks: totalChunks,
                chunk: chunk
            };
            
            // Add small delay between chunks to prevent overwhelming the server
            setTimeout(() => {
                this.socket.send(JSON.stringify(chunkMessage));
            }, i * 50);
        }
    }

    /**
     * 生成UUID
     * @return {string} UUID
     */
    generateUUID() {
        return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
            const r = Math.random() * 16 | 0;
            const v = c === 'x' ? r : (r & 0x3 | 0x8);
            return v.toString(16);
        });
    }
}

/**
 * 文件处理工具类
 * 提供文件读取、分块处理等功能
 */
class FileUtil {
    /**
     * 将文件读取为Base64编码字符串
     * @param {File} file 文件对象
     * @return {Promise<string>} Promise包含Base64编码的文件内容
     */
    static readFileAsBase64(file) {
        return new Promise((resolve, reject) => {
            const reader = new FileReader();
            
            reader.onload = () => {
                resolve(reader.result);
            };
            
            reader.onerror = () => {
                reject(new Error("文件读取失败"));
            };
            
            reader.readAsDataURL(file);
        });
    }
    
    /**
     * 将文件分块处理
     * @param {File} file 文件对象
     * @param {number} chunkSize 分块大小（字节）
     * @return {Promise<Array<string>>} Promise包含Base64编码的文件分块
     */
    static splitFileIntoChunks(file, chunkSize = 32 * 1024) {
        return new Promise((resolve, reject) => {
            const chunks = [];
            let offset = 0;
            const CHUNK_SIZE = chunkSize; // 32KB chunks by default
            
            const reader = new FileReader();
            
            reader.onload = (e) => {
                const data = e.target.result;
                chunks.push(data);
                
                offset += CHUNK_SIZE;
                if (offset < file.size) {
                    // Read next chunk
                    readNextChunk();
                } else {
                    // All chunks read
                    resolve(chunks);
                }
            };
            
            reader.onerror = (error) => {
                reject(error);
            };
            
            function readNextChunk() {
                const slice = file.slice(offset, offset + CHUNK_SIZE);
                reader.readAsDataURL(slice);
            }
            
            // Start reading
            readNextChunk();
        });
    }
    
    /**
     * 获取文件MIME类型
     * @param {File} file 文件对象
     * @return {string} MIME类型
     */
    static getMimeType(file) {
        return file.type || this.guessMimeTypeFromExtension(file.name);
    }
    
    /**
     * 根据文件扩展名猜测MIME类型
     * @param {string} filename 文件名
     * @return {string} MIME类型
     */
    static guessMimeTypeFromExtension(filename) {
        const ext = filename.split('.').pop().toLowerCase();
        const mimeTypes = {
            'jpg': 'image/jpeg',
            'jpeg': 'image/jpeg',
            'png': 'image/png',
            'gif': 'image/gif',
            'webp': 'image/webp',
            'mp4': 'video/mp4',
            'webm': 'video/webm',
            'mp3': 'audio/mpeg',
            'wav': 'audio/wav',
            'ogg': 'audio/ogg',
            'pdf': 'application/pdf',
            'doc': 'application/msword',
            'docx': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
            'xls': 'application/vnd.ms-excel',
            'xlsx': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
        };
        
        return mimeTypes[ext] || 'application/octet-stream';
    }
    
    /**
     * 根据MIME类型获取WebSocket内容类型
     * @param {string} mimeType MIME类型
     * @return {string} WebSocket内容类型
     */
    static getWebSocketContentType(mimeType) {
        if (mimeType.startsWith('image/')) {
            return 'image';
        } else if (mimeType.startsWith('video/')) {
            return 'video';
        } else if (mimeType.startsWith('audio/')) {
            return 'audio';
        } else {
            return 'file';
        }
    }
}

// 导出类供HTML页面使用
if (typeof window !== 'undefined') {
    window.WebSocketClient = WebSocketClient;
    window.FileUtil = FileUtil;
} 